home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / tnos / tnos100s / telnet.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-21  |  12.7 KB  |  623 lines

  1. /* Internet Telnet client
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4. /* Mods by PA0GRI */
  5. /* Mods by KO4KS */
  6. #include <stdio.h>
  7. #ifdef    __TURBOC__
  8. #include <io.h>
  9. #include <fcntl.h>
  10. #endif
  11. #include <conio.h>
  12. #include "global.h"
  13. #include "config.h"
  14. #include "mbuf.h"
  15. #include "socket.h"
  16. #include "telnet.h"
  17. #include "session.h"
  18. #include "proc.h"
  19. #include "tty.h"
  20. #include "commands.h"
  21. #include "netuser.h"
  22. #include "usock.h"
  23.  
  24. extern unsigned char SCREENwidth, SCREENlength;
  25. static int filemode __ARGS((FILE *fp,int mode));
  26. #ifndef CTLZ
  27. #define    CTLZ    26
  28. #endif
  29.  
  30. int Refuse_echo = 0;
  31. int Tn_cr_mode = 0;    /* if true turn <cr> to <cr-nul> */
  32.  
  33. static char *conversinit;
  34.  
  35. #ifdef    DEBUG
  36. char *T_options[] = {
  37.     "Transmit Binary",
  38.     "Echo",
  39.     "",
  40.     "Suppress Go Ahead",
  41.     "",
  42.     "Status",
  43.     "Timing Mark"
  44. };
  45. #endif
  46.  
  47. int usesplit = 0;    /* kludge for doconf */
  48.  
  49. #ifdef    MAILBOX
  50. /* Execute user BBS command */
  51. int
  52. dobbs(argc,argv,p)
  53. int argc;
  54. char *argv[];
  55. void *p;
  56. {
  57.     struct session *sp;
  58.     struct sockaddr_in fsocket;
  59.  
  60.     /*Make sure this comes from console - WG7J*/
  61.     if(Curproc->input != Command->input)
  62.         return 0;
  63.  
  64.     /* Allocate a session descriptor */
  65.     if((sp = newsession("Local BBS",TELNET,0)) == NULLSESSION){
  66.             tputs(TooManySessions);
  67.         return 1;
  68.     }
  69.     fsocket.sin_family = AF_INET;
  70.     if(argc < 3)
  71.         fsocket.sin_port = IPPORT_TELNET;
  72.     else
  73.         fsocket.sin_port = atoip(argv[2]);
  74.  
  75.     fsocket.sin_addr.s_addr = 0x7f000001L; /* 127.0.0.1 the loopback interface */
  76. #ifdef not again
  77.     if((fsocket.sin_addr.s_addr = Ip_addr) == 0){
  78.         tprintf(Badhost,sp->name);
  79.         keywait(NULLCHAR,1);
  80.         freesession(sp);
  81.         return 1;
  82.     }
  83. #endif
  84.     if((sp->s = socket(AF_INET,SOCK_STREAM,0)) == -1){
  85.         tputs(Nosock);
  86.         keywait(NULLCHAR,1);
  87.         freesession(sp);
  88.         return 1;
  89.     }
  90.     return tel_connect(sp,(char *)&fsocket,SOCKSIZE);
  91. }
  92. #endif /*MAILBOX*/
  93.  
  94.  
  95. #ifdef RLOGINSERV
  96. /* Execute remote login command */
  97. int
  98. dorlogin(argc,argv,p)
  99. int argc;
  100. char *argv[];
  101. void *p;
  102. {
  103.     free (argv[0]);
  104.     argv[0] = strdup ("telnet");
  105.     if (argv[2])
  106.         free (argv[2]);
  107.     argv[2] = strdup ("513");
  108.     if (!argv[1])
  109.         argv[1] = strdup (Hostname);
  110.     usesplit = 1;
  111.     return dotelnet(3,argv,p);
  112. }
  113. #endif
  114.  
  115. #ifdef ALLSESSIONS
  116. /* Execute user conference command */
  117. int
  118. doconf(argc,argv,p)
  119. int argc;
  120. char *argv[];
  121. void *p;
  122. {
  123. char buf[32], buf2[32], *cptr;
  124. int i = 0;
  125.  
  126.     free (argv[0]);
  127.     argv[0] = strdup ("telnet");
  128.     strcpy (buf2, Hostname);
  129.     cptr = strchr (buf2, '.');
  130.     if (cptr)
  131.         *cptr = 0;
  132.     strlwr (buf2);
  133.     sprintf (buf, "/NA %s %s\n", buf2, (argv[2]) ? argv[2] : "-1");
  134.     if (argv[2])
  135.         free (argv[2]);
  136.     argv[2] = strdup ("3600");
  137.     if (!argv[1])
  138.         argv[1] = strdup (buf2);
  139.     conversinit = buf;
  140.     usesplit = 1;
  141.     return dotelnet(3,argv,p);
  142. }
  143.  
  144. /* Execute user telnet command */
  145. int
  146. dotelnet(argc,argv,p)
  147. int argc;
  148. char *argv[];
  149. void *p;
  150. {
  151.     struct session *sp;
  152.     struct sockaddr_in fsocket;
  153.         int split;
  154.  
  155.     split = usesplit;
  156.     usesplit = 0;
  157.  
  158.     /*Make sure this comes from console - WG7J*/
  159.     if(Curproc->input != Command->input)
  160.         return 0;
  161.  
  162. #ifdef ALLSERV
  163.     if((strlen(argv[0]) > 1) && (argv[0][1] == 't')) /* tty-link command */
  164.         split = 1;
  165. #endif
  166.  
  167.     /* Allocate a session descriptor */
  168.     if((sp = newsession(argv[1],TELNET,split)) == NULLSESSION)    {
  169.             tputs(TooManySessions);
  170.         return 1;
  171.     }
  172.     fsocket.sin_family = AF_INET;
  173.     if(argc < 3)    {
  174.         if(split)
  175.             fsocket.sin_port = IPPORT_TTYLINK;
  176.         else
  177.             fsocket.sin_port = IPPORT_TELNET;
  178.     } else
  179.         fsocket.sin_port = atoip(argv[2]);
  180.  
  181.     tprintf("Resolving %s... ",sp->name);
  182.     if((fsocket.sin_addr.s_addr = resolve(sp->name)) == 0){
  183.         tprintf(Badhost,sp->name);
  184.         keywait(NULLCHAR,1);
  185.         freesession(sp);
  186.         return 1;
  187.     }
  188.     if((sp->s = socket(AF_INET,SOCK_STREAM,0)) == -1){
  189.         tputs(Nosock);
  190.         keywait(NULLCHAR,1);
  191.         freesession(sp);
  192.         return 1;
  193.     }
  194.     return tel_connect(sp,(char *)&fsocket,SOCKSIZE);
  195. }
  196. #endif
  197.  
  198. /* Generic interactive connect routine, used by Telnet, AX.25, NET/ROM */
  199. int
  200. tel_connect(sp,fsocket,len)
  201. struct session *sp;
  202. char *fsocket;
  203. int len;
  204. {
  205.     unsigned int index;
  206.     struct telnet tn;
  207.  
  208.     index = sp - Sessions;
  209.     memset((char *)&tn,0,sizeof(tn));
  210.     tn.eolmode = Tn_cr_mode;
  211.     tn.session = sp;    /* Upward pointer */
  212.     sp->cb.telnet = &tn;    /* Downward pointer */
  213.     sockmode(sp->s,SOCK_ASCII);    /* Default to ascii mode */
  214.  
  215.     tprintf("Trying %s...\n",psocket((struct sockaddr *)fsocket));
  216.     if(connect(sp->s,fsocket,len) == -1){
  217.           tprintf("%s session %u failed: %s errno %d\n",
  218.          Sestypes[sp->type], index, sockerr(sp->s),errno);
  219.  
  220.         keywait(NULLCHAR,1);
  221.         freesession(sp);
  222.         return 1;
  223.     }
  224.     tprintf("%s session ",Sestypes[sp->type]);
  225.     tprintf("%u connected to %s\n",index,sp->name);
  226.     tnrecv(&tn);
  227.     return 0;
  228. }
  229.  
  230. /* Telnet input routine, common to both telnet and ttylink */
  231. void
  232. tnrecv(tn)
  233. struct telnet *tn;
  234. {
  235. int c,s,index;
  236. struct session *sp;
  237. char *cp;
  238. #ifndef TNOS_68K
  239. struct text_info tr;
  240. unsigned char attr;
  241. #endif
  242. int bits, mode;
  243. struct usock *up;
  244.  
  245.     sp = tn->session;
  246.     s = sp->s;
  247.  
  248.     index = sp - Sessions;
  249.  
  250.     /* Fork off the transmit process */
  251.     sp->proc1 = newproc("tel_out",1024,tel_output,0,tn,NULL,0);
  252.  
  253.     /* Process input on the connection */
  254.     while((c = recvchar(s)) != -1){
  255.         if(c != IAC){
  256. #ifdef notdef
  257.             /* Allow international character sets to pass - WG7J */
  258.             /* Ordinary character */
  259.             if(!tn->remote[TN_TRANSMIT_BINARY])
  260.                 c &= 0x7f;
  261. #endif
  262.             tputc((char)c);
  263.             continue;
  264.         }
  265.         /* IAC received, get command sequence */
  266.         c = recvchar(s);
  267.         switch(c){
  268.         case WILL:
  269.             c = recvchar(s);
  270.             willopt(tn,c);
  271.             break;
  272.         case WONT:
  273.             c = recvchar(s);
  274.             wontopt(tn,c);
  275.             break;
  276.         case DO:
  277.             c = recvchar(s);
  278.             doopt(tn,c);
  279.             break;
  280.         case DONT:
  281.             c = recvchar(s);
  282.             dontopt(tn,c);
  283.             break;
  284. #ifdef LZW
  285.         case COMPRESSED:
  286.             mode = recvchar(s);
  287.             bits = recvchar(s);
  288.             mode = (mode == 'f') ? 1 : 0;
  289.             if (bits < 9 || bits > 16)
  290.                 break;
  291.             if((up = itop(s)) == NULLUSOCK)
  292.                 break;
  293. /*            if(socklen(s,0))    */ /* discard any remaining input */
  294. /*                recv_mbuf(s,NULL,0,NULLCHAR,0);    */
  295.             if(up->zout == NULLLZW)
  296.                     lzwinit (s, bits, mode);
  297.             else
  298.                 lzwfree (up);
  299.             break;
  300. #endif
  301.         case CLEARSCREEN:
  302. #ifndef TNOS_68K
  303.             if (!sp->split)    {
  304.                 window(1,1,SCREENwidth,SCREENlength);
  305.                 clrscr ();        /* clear the screen */
  306.                 window(1,SCREENlength - 1,SCREENwidth,SCREENlength);    /* changed 1,1->1,24 */
  307.                 gettextinfo(&tr);
  308.                 attr = ((tr.attribute & 0x0f) << 4) + ((tr.attribute & 0x70) >> 4);
  309.                 textattr (attr);
  310.                 clrscr ();
  311.                 cputs("_\b");
  312.                 window(1,1 + sp->screen->statline,SCREENwidth,SCREENlength - 2);
  313.                 textattr (tr.attribute);
  314.                 sp->split = 1;
  315.                 if (sp->screen->statline)
  316.                     displayStatLine (0, 1);
  317.                 }
  318. #endif
  319.             break; 
  320.         case CLEARSPLIT:
  321.                 clrchatline (sp);
  322.             break; 
  323.         case IAC:    /* Escaped IAC */
  324.             tputc(IAC);
  325.             break;
  326.         }
  327.     }
  328.     /* A close was received from the remote host.
  329.      * Notify the user, kill the output task and wait for a response
  330.      * from the user before freeing the session.
  331.      */
  332.     sockmode(sp->output,SOCK_ASCII); /* Restore newline translation */
  333.     cp = sockerr(s);
  334.     tprintf("%s session %u", Sestypes[sp->type],index);
  335.     tprintf(" closed: %s\n", cp != NULLCHAR ? cp : "EOF");
  336.     killproc(sp->proc1);
  337.     sp->proc1 = NULLPROC;
  338.     close_s(sp->s);
  339.     sp->s = -1;
  340.     keywait(NULLCHAR,1);
  341.     freesession(sp);
  342. }
  343.  
  344. /* User telnet output task, started by user telnet command */
  345. void
  346. tel_output(unused,tn1,p)
  347. int unused;
  348. void *tn1;
  349. void *p;
  350. {
  351. struct session *sp;
  352. int c;
  353. struct telnet *tn;
  354.  
  355.     tn = (struct telnet *)tn1;
  356.     sp = tn->session;
  357.  
  358.     if (conversinit)    {
  359.         usprintf (sp->s, conversinit);
  360.         conversinit = 0;
  361.     }
  362.     /* Send whatever's typed on the terminal */
  363.     while((c = recvchar(sp->input)) != EOF){
  364.         usputc(sp->s,(char)c);
  365.         if(!tn->remote[TN_ECHO] && sp->record != NULLFILE)
  366.             putc(c,sp->record);
  367.  
  368.         /* By default, output is transparent in remote echo mode.
  369.          * If eolmode is set, turn a cr into cr-null.
  370.          * This can only happen when in remote echo (raw) mode, since
  371.          * the tty driver normally maps \r to \n in cooked mode.
  372.          */
  373.         if(c == '\r' && tn->eolmode)
  374.             usputc(sp->s,'\0');
  375.  
  376.         if(tn->remote[TN_ECHO])
  377.             usflush(sp->s);
  378.     }
  379.     /* Make sure our parent doesn't try to kill us after we exit */
  380.     sp->proc1 = NULLPROC;
  381. }
  382.  
  383. int
  384. doecho(argc,argv,p)
  385. int argc;
  386. char *argv[];
  387. void *p;
  388. {
  389.     if(argc < 2){
  390.         if(Refuse_echo)
  391.             tprintf("Refuse\n");
  392.         else
  393.             tprintf("Accept\n");
  394.     } else {
  395.         if(argv[1][0] == 'r')
  396.             Refuse_echo = 1;
  397.         else if(argv[1][0] == 'a')
  398.             Refuse_echo = 0;
  399.         else
  400.             return -1;
  401.     }
  402.     return 0;
  403. }
  404. /* set for unix end of line for remote echo mode telnet */
  405. int
  406. doeol(argc,argv,p)
  407. int argc;
  408. char *argv[];
  409. void *p;
  410. {
  411.     if(argc < 2){
  412.         if(Tn_cr_mode)
  413.             tprintf("null\n");
  414.         else
  415.             tprintf("standard\n");
  416.     } else {
  417.         if(argv[1][0] == 'n')
  418.             Tn_cr_mode = 1;
  419.         else if(argv[1][0] == 's')
  420.             Tn_cr_mode = 0;
  421.         else {
  422.             tprintf("Usage: %s [standard|null]\n",argv[0]);
  423.             return -1;
  424.         }
  425.     }
  426.     return 0;
  427. }
  428.  
  429. /* The guts of the actual Telnet protocol: negotiating options */
  430. void
  431. willopt(tn,opt)
  432. struct telnet *tn;
  433. int opt;
  434. {
  435.     int ack;
  436.  
  437. #ifdef    DEBUG
  438.     printf("recv: will ");
  439.     if(uchar(opt) <= NOPTIONS)
  440.         printf("%s\n",T_options[opt]);
  441.     else
  442.         printf("%u\n",opt);
  443. #endif
  444.     
  445.     switch(uchar(opt)){
  446.     case TN_TRANSMIT_BINARY:
  447.     case TN_ECHO:
  448.     case TN_SUPPRESS_GA:
  449.         if(tn->remote[uchar(opt)] == 1)
  450.             return;        /* Already set, ignore to prevent loop */
  451.         if(uchar(opt) == TN_ECHO){
  452.             if(Refuse_echo){
  453.                 /* User doesn't want to accept */
  454.                 ack = DONT;
  455.                 break;
  456.             } else {
  457.                 /* Put tty into raw mode */
  458.                 tn->session->ttystate.edit = 0;
  459.                 tn->session->ttystate.echo = 0;
  460.                 sockmode(tn->session->s,SOCK_BINARY);
  461.                 sockmode(tn->session->input,SOCK_BINARY);
  462.                 sockmode(tn->session->output,SOCK_BINARY);
  463.                 if(tn->session->record != NULLFILE)
  464.                     filemode(tn->session->record,SOCK_BINARY);
  465.  
  466.             }
  467.         }
  468.         tn->remote[uchar(opt)] = 1;
  469.         ack = DO;            
  470.         break;
  471.     default:
  472.         ack = DONT;    /* We don't know what he's offering; refuse */
  473.     }
  474.     answer(tn,ack,opt);
  475. }
  476. void
  477. wontopt(tn,opt)
  478. struct telnet *tn;
  479. int opt;
  480. {
  481. #ifdef    DEBUG
  482.     printf("recv: wont ");
  483.     if(uchar(opt) <= NOPTIONS)
  484.         printf("%s\n",T_options[uchar(opt)]);
  485.     else
  486.         printf("%u\n",uchar(opt));
  487. #endif
  488.     if(uchar(opt) <= NOPTIONS){
  489.         if(tn->remote[uchar(opt)] == 0)
  490.             return;        /* Already clear, ignore to prevent loop */
  491.         tn->remote[uchar(opt)] = 0;
  492.         if(uchar(opt) == TN_ECHO){
  493.             /* Put tty into cooked mode */
  494.             tn->session->ttystate.edit = 1;
  495.             tn->session->ttystate.echo = 1;
  496.             sockmode(tn->session->s,SOCK_ASCII);
  497.             sockmode(tn->session->input,SOCK_ASCII);
  498.             sockmode(tn->session->output,SOCK_ASCII);
  499.             if(tn->session->record != NULLFILE)
  500.                 filemode(tn->session->record,SOCK_ASCII);
  501.         }
  502.     }
  503.     answer(tn,DONT,opt);    /* Must always accept */
  504. }
  505. void
  506. doopt(tn,opt)
  507. struct telnet *tn;
  508. int opt;
  509. {
  510.     int ack;
  511.  
  512. #ifdef    DEBUG
  513.     printf("recv: do ");
  514.     if(uchar(opt) <= NOPTIONS)
  515.         printf("%s\n",T_options[uchar(opt)]);
  516.     else
  517.         printf("%u\n",uchar(opt));
  518. #endif
  519.     switch(uchar(opt)){
  520.     case TN_SUPPRESS_GA:
  521.         if(tn->local[uchar(opt)] == 1)
  522.             return;        /* Already set, ignore to prevent loop */
  523.         tn->local[uchar(opt)] = 1;
  524.         ack = WILL;
  525.         break;
  526.     default:
  527.         ack = WONT;    /* Don't know what it is */
  528.     }
  529.     answer(tn,ack,opt);
  530. }
  531. void
  532. dontopt(tn,opt)
  533. struct telnet *tn;
  534. int opt;
  535. {
  536. #ifdef    DEBUG
  537.     printf("recv: dont ");
  538.     if(uchar(opt) <= NOPTIONS)
  539.         printf("%s\n",T_options[uchar(opt)]);
  540.     else
  541.         printf("%u\n",uchar(opt));
  542. #endif
  543.     if(uchar(opt) <= NOPTIONS){
  544.         if(tn->local[uchar(opt)] == 0){
  545.             /* Already clear, ignore to prevent loop */
  546.             return;
  547.         }
  548.         tn->local[uchar(opt)] = 0;
  549.     }
  550.     answer(tn,WONT,opt);
  551. }
  552. void
  553. answer(tn,r1,r2)
  554. struct telnet *tn;
  555. int r1,r2;
  556. {
  557.     char s[3];
  558.  
  559. #ifdef    DEBUG
  560.     switch(r1){
  561.     case WILL:
  562.         printf("sent: will ");
  563.         break;
  564.     case WONT:
  565.         printf("sent: wont ");
  566.         break;
  567.     case DO:
  568.         printf("sent: do ");
  569.         break;
  570.     case DONT:
  571.         printf("sent: dont ");
  572.         break;
  573.     }
  574.     if(r2 <= NOPTIONS)
  575.         printf("%s\n",T_options[r2]);
  576.     else
  577.         printf("%u\n",r2);
  578. #endif
  579.  
  580.     s[0] = IAC;
  581.     s[1] = r1;
  582.     s[2] = r2;
  583.     send(tn->session->s,s,3,0);
  584. }
  585. #ifdef    __TURBOC__
  586. /* Set end-of-line translation mode on file */
  587. static int
  588. filemode(fp,mode)
  589. FILE *fp;
  590. int mode;
  591. {
  592.     int omode;
  593.  
  594.     if(fp == NULLFILE)
  595.         return -1;
  596.  
  597.     if(fp->flags & _F_BIN)
  598.         omode = SOCK_BINARY;
  599.     else
  600.         omode = SOCK_ASCII;
  601.  
  602.     switch(mode){
  603.     case SOCK_BINARY:
  604.         fp->flags = _F_BIN;
  605.         setmode(fileno(fp),O_BINARY);
  606.         break;
  607.     case SOCK_ASCII:
  608.         fp->flags &= ~_F_BIN;
  609.         setmode(fileno(fp),O_TEXT);
  610.         break;
  611.     }
  612.     return omode;
  613. }
  614. #else
  615. static int
  616. filemode(fp,mode)
  617. FILE *fp;
  618. int mode;
  619. {
  620.     return 0;
  621. }
  622. #endif
  623.